package dbmanager

import (
	"database/sql"
	"fmt"
	"reflect"
	"strings"
	"time"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/msgdef"
	"gitee.com/night-tc/gobige/msgdef/protomsg"
	"github.com/gomodule/redigo/redis"
)

/*
init.go 文件提供了数据库管理器的初始化功能，包含了一些常用的数据库操作工具函数。
该文件主要用于处理与数据库相关的通用操作，如生成键名、解析键名、发送消息到数据库服务器等。
*/

var (
	Err_Player_Load = common.NewError(-1, "玩家数据加载失败 %s")
)

// GetRowKeyNameByPID 根据表名生成单行数据的键名
func GetRowKeyNameByPID(tname string) string {
	return tname
}

// GetRowKeyNameByUID 根据表名和用户ID生成多行数据的键名
func GetRowKeyNameByUID(tname string, uid uint64) string {
	return fmt.Sprintf("%s:%d", tname, uid)
}

// GetRowKeyName 根据数据模型生成键名，支持单行和多行数据
func GetRowKeyName(data IDataBaseModel) string {
	if v, ok := data.(IPlayerSubBase); ok {
		return GetRowKeyNameByUID(v.TableName(), v.GetID())
	} else {
		return GetRowKeyNameByPID(data.TableName())
	}
}

// GetKeyNameResolve 解析键名，返回表名和用户ID
func GetKeyNameResolve(keyname string) (table string, uid uint64) {
	tmpli := strings.Split(keyname, ":")
	if len(tmpli) == 2 {
		uid = common.NewString(tmpli[1]).ToUint64V()
	}
	return tmpli[0], uid
}

// PostDBPlayer 发送消息到数据库服务器，支持重试机制
func PostDBPlayer(pid, nttid uint64, reqMsg msgdef.IMsg) {
	dbutil := NewEntityUtilDBData(pid)
	var srvID uint64
	var err error
	for i := 0; i < 3; i++ {
		srvID, err = GetDBServer(dbutil, nttid)
		if err != nil {
			continue
		}
		break
	}
	if err != nil {
		logger.Errorf("PostDBPlayer pid:%d err:%s", pid, err)
		return
	}

	if dbdata, ok := reqMsg.(*protomsg.DBUpUserDatasReq); ok {
		if len(dbdata.DBList)+len(dbdata.DelList) > DataList_Count {
			dblist := dbdata.DBList
			dellist := dbdata.DelList
			for len(dblist)+len(dellist) > 0 {
				msg := new(protomsg.DBUpUserDatasReq)
				msg.PID = dbdata.PID
				msg.EntityID = nttid
				msg.SpaceID = dbdata.SpaceID
				msg.SrvID = dbdata.SrvID
				if len(dblist) > 50 {
					msg.DBList = dblist[:50]
					dblist = dblist[50:]
				} else if len(dblist) > 0 {
					msg.DBList = dblist
					dblist = dblist[0:0]
				} else if len(dellist) > 50 {
					msg.DelList = dellist[:50]
					dellist = dellist[50:]
				} else if len(dellist) > 0 {
					msg.DelList = dellist
					dellist = dellist[0:0]
				}
				_ = global.GetSrvInst().PostMsgToEntity(srvID, 0, 0, msg)
			}
		} else {
			_ = global.GetSrvInst().PostMsgToEntity(srvID, 0, 0, reqMsg)
		}
	} else {
		_ = global.GetSrvInst().PostMsgToEntity(srvID, 0, 0, reqMsg)
	}
}

// redisFullData 将Redis中的数据填充到反射值中，支持多种数据类型
func redisFullData(fmd reflect.Value, v []byte) error {
	switch fmd.Kind() {
	case reflect.Bool:
		tv, _ := redis.Bool(v, nil)
		fmd.SetBool(tv)
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		tv, _ := redis.Int64(v, nil)
		fmd.SetInt(tv)
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		tv, _ := redis.Uint64(v, nil)
		fmd.SetUint(tv)
	case reflect.Float32, reflect.Float64:
		tv, _ := redis.Float64(v, nil)
		fmd.SetFloat(tv)
	case reflect.String:
		tv, _ := redis.String(v, nil)
		fmd.SetString(tv)
	case reflect.Slice:
		fmd.SetBytes(v)
	case reflect.Struct:
		if val, ok := fmd.Addr().Interface().(sql.Scanner); ok {
			if err := val.Scan(v); err != nil {
				return err
			}
		} else if _, ok1 := fmd.Interface().(time.Time); ok1 {
			if t, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", string(v)); err == nil {
				fmd.Set(reflect.ValueOf(t))
			} else {
				_ = err
			}
		}
	case reflect.Map:
		if val, ok := fmd.Addr().Interface().(sql.Scanner); ok {
			if err := val.Scan(v); err != nil {
				return err
			}
		}
	}
	return nil
}